#ifndef PRIMITIVELINEBATCH_H_INCLUDED
#define PRIMITIVELINEBATCH_H_INCLUDED

//predecl
namespace cvImmediateModeRenderer { class LineBatch; };

//includes
#include <vector>
#include <General/cvMemory.h>
#include "../Renderable.h"
#include "Line.h"
#include "../CollectionNode.h"
#include "../CollectionTypes.h"

namespace cvImmediateModeRenderer
{
	// final class.
	class LineBatch : public cvRenderInterface::CollectionNode
	{
		public:
			/// create read-write collection.
			static LineBatch * create();
			/// create write-once collection.
			static LineBatch * createSingleshot();

			/// write-once cvImmediateModeRenderer::Line
			virtual cvRenderInterface::Renderable * writeRenderable();

			virtual void destroy();

			static void purgeMemoryPool();

			/// Drawing order #3
			virtual void enableSort(bool state);
			virtual bool sort();

			/// Collections #4
			virtual const Collection collectionType() const;

			/// applies single node directly into the collection. [#2 node allocator]
			// used to do direct allocation of Renderable into its Collection.
			// pre-condition: node *must not* have been previously fetched into any collection.
			virtual void fetchNode( cvRenderInterface::Renderable * prim );

			/// applies nodes into the collection from main rendering list.	[begin, end) [#4 Rendering list managment]
			// pre-condition: range must only contain same collectionType() nodes.
			// post-condition: range must be removed from the orginal list as contained collections are destroyed
			// and nodes are moved into this collection.
			virtual void fetchNodes( cvRenderInterface::renderinglist_t::iterator begin,
									 cvRenderInterface::renderinglist_t::iterator end );

			virtual void detachNode( cvRenderInterface::Renderable * prim);

			virtual void processCollect(const cvObjects::BaseCameraObject * camera);
			virtual void processTransfer();
			virtual void processRender();

			// locked rendering
			virtual void lockTransfer(bool enable);


		protected:
			LineBatch();
			~LineBatch();

		private:
			void * operator new(size_t);		// <never implement!>
			void operator delete(void*);		// <never implement!>
			void * operator new[] (size_t);		// <never implement!>
			void operator delete[] (void*);		// <never implement!>

			typedef std::vector<line_struct, cvPoolAllocator<line_struct>::CON> structarray_t;

			static cvPool m_pool;	// pool for LineBatch instances.

			// TODO: remapping over 2048 read-write nodes gets _very very slow_, as current algorithm is linear. (or even worse)
			// Use multiple constant sized buffers which are then combined at processTransfer()
			// Gaining the buffer from single primitive is done via boost::unordered_map and custoom hash func.
			// unordered_map<> m_fullbuffers;		// full buffers that can be simply binary copied to GPU
			// unordered_map<> m_partialbuffers;	// partial buffers require picking the primitives from RAM.
			// while this collection is not being used, it is defragmented on background.

			/// primitive storgate array.
			structarray_t m_storgatearray;

			size_t m_primitive_cnt;
			bool m_is_storgatedirty;
			bool m_do_sort, m_trigger_sort;
			// collected primitives
			//std::vector<Line*, cvPoolAllocator<Line*>::CON> m_collectednodes;
			// drawing array
			//structarray_t m_drawarray;

			/// ##LineBatch internal procedures##

			size_t __alloc_chunk_size(size_t minrequest);

			/// Resizes m_storgatearray.
			/// Space is allocated at least for @param size line_structs
			void __reserve(size_t size);

			/// Remaps m_collectionlist into (fresh) buffer.
			/// @param reservespace how much capacity the new buffer should have. Zero keeps the current capacity.
			/// @param force_realloc discards old buffer and blindly reallocates (for more capacity) the buffer.
			void __remap(size_t reservespace, bool force_realloc = false);

			Line * m_singleshot_target;

			GLuint m_locked_renderlist;
	};

};

#endif // PRIMITIVELINEBATCH_H_INCLUDED
